﻿/********************************************************************
	文件：CylinderShape.cs
    作者：Pangdudu
    日期：2021/03/02
    描述: 圆柱体的形状
*********************************************************************/

using UnityEngine;

namespace ShapeMesh
{
    public class CylinderShape : Shape
    {
        private static readonly string _cylinderMeshName = "Cylinder Mesh";//mesh的名称

        #region private members
        private readonly float _height;//圆柱体的高度
        private readonly float _radius;//圆柱体的半径

        private readonly int _circularSideCount;//保存圆分割的边数
        #endregion

        #region ctor
        public CylinderShape(float height, float radius, MeshPivot meshPivot) : base(meshPivot, _cylinderMeshName)
        {
            _height = height;
            _radius = radius;

            _vertexOffset = GetVertexOffset();
            _circularSideCount = GetCircularSideCount(radius);
        }
        #endregion

        #region override functions
        /// <summary>
        /// 根据mesh中心点的位置，获得顶点位置的偏移量
        /// </summary>
        /// <returns></returns>
        protected sealed override Vector3 GetVertexOffset()
        {
            return _meshPivot switch
            {
                MeshPivot.Center => Vector3.zero,
                MeshPivot.Top => new Vector3(0, _height, 0) * 0.5f,
                MeshPivot.Bottom => new Vector3(0, -_height, 0) * 0.5f,
                MeshPivot.Left => new Vector3(-_radius, 0, 0),
                MeshPivot.Right => new Vector3(_radius, 0, 0),
                MeshPivot.Front => new Vector3(0, 0, _radius),
                MeshPivot.Back => new Vector3(0, 0, -_radius),
                _ => Vector3.zero
            };
        }

        /// <summary>
        /// 获得顶点的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector3[] GetVertices()
        {
            var curIndex = 0;//当前索引
            var arrayLen = (_circularSideCount + 1) * 2 + _circularSideCount * 2 + 2;//数组的长度
            var vertices = new Vector3[arrayLen];
            //底面
            vertices[curIndex++] = new Vector3(0, -_height * 0.5f, 0) - _vertexOffset;//圆心
            for (var i = 0; i < _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;//弧度
                var cos = Mathf.Cos(rad) * _radius;
                var sin = Mathf.Sin(rad) * _radius;
                vertices[curIndex++] = new Vector3(cos, -_height * 0.5f, sin) - _vertexOffset;
            }
            //顶面
            vertices[curIndex++] = new Vector3(0, _height * 0.5f, 0) - _vertexOffset;//圆心
            for (var i = 0; i < _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;//弧度
                var cos = Mathf.Cos(rad) * _radius;
                var sin = Mathf.Sin(rad) * _radius;
                vertices[curIndex++] = new Vector3(cos, _height * 0.5f, sin) - _vertexOffset;
            }
            //侧面
            var sideStartIndex = curIndex;
            for (var i = 0; i < _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;//弧度
                var cos = Mathf.Cos(rad) * _radius;
                var sin = Mathf.Sin(rad) * _radius;
                vertices[curIndex++] = new Vector3(cos, -_height * 0.5f, sin) - _vertexOffset;
                vertices[curIndex++] = new Vector3(cos, _height * 0.5f, sin) - _vertexOffset;
            }
            vertices[curIndex++] = vertices[sideStartIndex];
            vertices[curIndex] = vertices[sideStartIndex + 1];
            return vertices;
        }

        /// <summary>
        /// 获得法线方向的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector3[] GetNormals()
        {
            var curIndex = 0;
            var arrayLen = (_circularSideCount + 1) * 2 + _circularSideCount * 2 + 2;
            var normals = new Vector3[arrayLen];
            //底面
            for (var i = 0; i <= _circularSideCount; i++)
            {
                normals[curIndex++] = Vector3.down;
            }
            //顶面
            for (var i = 0; i <= _circularSideCount; i++)
            {
                normals[curIndex++] = Vector3.up;
            }
            //侧面
            for (var i = 0; i <= _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;
                var cos = Mathf.Cos(rad);
                var sin = Mathf.Sin(rad);
                normals[curIndex++] = new Vector3(cos, 0, sin);
                normals[curIndex++] = new Vector3(cos, 0, sin);
            }
            return normals;
        }

        /// <summary>
        /// 获得三角面顶点的索引
        /// </summary>
        /// <returns></returns>
        protected override int[] GetTriangles()
        {
            var curIndex = 0;
            var arrayLen = _circularSideCount * 3 + _circularSideCount * 3 + _circularSideCount * 3 * 2;
            var triangles = new int[arrayLen];
            //底面
            for (var i = 1; i < _circularSideCount; i++)
            {
                triangles[curIndex++] = 0;
                triangles[curIndex++] = i;
                triangles[curIndex++] = i + 1;
            }
            triangles[curIndex++] = 0;
            triangles[curIndex++] = _circularSideCount;
            triangles[curIndex++] = 1;
            //顶面
            for (var i = _circularSideCount + 2; i < _circularSideCount * 2 + 1; i++)
            {
                triangles[curIndex++] = _circularSideCount + 1;
                triangles[curIndex++] = i + 1;
                triangles[curIndex++] = i;
            }
            triangles[curIndex++] = _circularSideCount + 1;
            triangles[curIndex++] = _circularSideCount + 2;
            triangles[curIndex++] = _circularSideCount * 2 + 1;
            //侧面
            var startIndex = _circularSideCount * 2 + 2;
            for (var i = 0; i < _circularSideCount; i++)
            {
                triangles[curIndex++] = startIndex;
                triangles[curIndex++] = startIndex + 1;
                triangles[curIndex++] = startIndex + 3;

                triangles[curIndex++] = startIndex + 3;
                triangles[curIndex++] = startIndex + 2;
                triangles[curIndex++] = startIndex;

                startIndex += 2;
            }
            return triangles;
        }

        /// <summary>
        /// 获得UV坐标的数据集合
        /// </summary>
        /// <returns></returns>
        protected override Vector2[] GetUVs()
        {
            var curIndex = 0;
            var arrayLen = (_circularSideCount + 1) * 2 + (_circularSideCount + 1) * 2;
            var uvs = new Vector2[arrayLen];
            //底面
            uvs[curIndex++] = new Vector2(0.5f, 0.5f);
            for (var i = 0; i < _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;
                var cos = Mathf.Cos(rad);
                var sin = Mathf.Sin(rad);
                uvs[curIndex++] = new Vector2(cos, sin) * 0.5f + new Vector2(0.5f, 0.5f);
            }
            //顶面
            uvs[curIndex++] = new Vector2(0.5f, 0.5f);
            for (var i = 0; i < _circularSideCount; i++)
            {
                var rad = i * 1.0f / _circularSideCount * Mathf.PI * 2;
                var cos = Mathf.Cos(rad);
                var sin = Mathf.Sin(rad);
                uvs[curIndex++] = new Vector2(cos, sin) * 0.5f + new Vector2(0.5f, 0.5f);
            }
            //侧面
            var value = 1.0f / _circularSideCount;
            for (var i = 0; i <= _circularSideCount; i++)
            {
                uvs[curIndex++] = new Vector2(i * value, 0);
                uvs[curIndex++] = new Vector2(i * value, 1);
            }
            return uvs;
        }
        #endregion
    }
}